/*
 * Copyright 2021 The happyProxy Project
 *
 * The happyProxy Project licenses this file to you under the Apache License,
 * version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *   https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */
package com.sinosoft.lingkang.happyproxy.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.NettyRuntime;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;

/**
 * @Author 绫小路
 * @Date 2021/2/22
 */
public class DefaultHappyProxyServer {

  private static final InternalLogger logger = InternalLoggerFactory.getInstance(DefaultHappyProxyServer.class);
  private HttpAuthorization authorization;
  private HttpProxyServerRequestFilter requestFilter;
  private int port = 8888;
  private int bossThread = 1;
  private int workerThread = NettyRuntime.availableProcessors() * 2;
  private HttpProxyServerFlowCount httpProxyServerFlowCount;


  public DefaultHappyProxyServer setHttpProxyServerFlowCount(HttpProxyServerFlowCount httpProxyServerFlowCount) {
    this.httpProxyServerFlowCount = httpProxyServerFlowCount;
    return this;
  }

  public DefaultHappyProxyServer setAuthorization(HttpAuthorization authorization) {
    this.authorization = authorization;
    return this;
  }

  public DefaultHappyProxyServer setRequestFilter(HttpProxyServerRequestFilter requestFilter) {
    this.requestFilter = requestFilter;
    return this;
  }

  public DefaultHappyProxyServer setPort(int port) {
    this.port = port;
    return this;
  }

  public DefaultHappyProxyServer setBossThread(int nThreads) {
    if (nThreads <= 0) {
      this.workerThread = 1;
    }
    int max = NettyRuntime.availableProcessors();
    if (nThreads > max) {
      this.workerThread = max;
    }
    return this;
  }

  public DefaultHappyProxyServer setWorkerThread(int nThreads) {
    if (nThreads <= 0) {
      this.bossThread = 1;
    }
    int max = NettyRuntime.availableProcessors() * 2;
    if (nThreads > max) {
      this.workerThread = max;
    }
    return this;
  }


  private EventLoopGroup bossGroup;
  private EventLoopGroup workerGroup;

  //启动
  public void start() {
    logger.info("Happy proxy start!");
    try {
      DefaultProxyServerInitializer initializer = new DefaultProxyServerInitializer();
      init(initializer);

      bossGroup = new NioEventLoopGroup(bossThread);
      workerGroup = new NioEventLoopGroup(workerThread);
      ServerBootstrap b = new ServerBootstrap();
      b.group(bossGroup, workerGroup)
          .channel(NioServerSocketChannel.class)
          .childHandler(initializer);
      b.bind(port).sync().channel().closeFuture().sync();
    } catch (InterruptedException e) {
      logger.error("start fail!");
      logger.error(e);
    } finally {
      bossGroup.shutdownGracefully();
      workerGroup.shutdownGracefully();
    }
  }

  //关闭
  public void shutdown() {
    if (!bossGroup.isShutdown()) {
      bossGroup.shutdownGracefully();
    }
    if (!workerGroup.isShutdown()) {
      workerGroup.shutdownGracefully();
    }
    logger.warn("Happy proxy shutdown!");
  }

  private void init(DefaultProxyServerInitializer initializer) {
    if (authorization != null) {
      initializer.setAuthorization(authorization);
    }
    if (requestFilter != null) {
      initializer.setRequestFilter(requestFilter);
    }
    if (httpProxyServerFlowCount != null) {
      initializer.setHttpProxyServerFlowCount(httpProxyServerFlowCount);
    }
  }
}
